/*
 * CC3OpenGLES11Capabilities.m
 *
 * cocos3d 0.6.1
 * Author: Bill Hollings
 * Copyright (c) 2010-2011 The Brenwill Workshop Ltd. All rights reserved.
 * http://www.brenwill.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * http://en.wikipedia.org/wiki/MIT_License
 * 
 * See header file CC3OpenGLES11Capabilities.h for full API documentation.
 */

#include "CC3OpenGLES11Capabilities.h"
#include "CC3OpenGLES11Engine.h"


#pragma mark -
#pragma mark CC3OpenGLES11StateTrackerServerCapability

//@implementation CC3OpenGLES11StateTrackerServerCapability
//
//-(void) setGLValue {
//	if (value) {
//		glEnable(name);
//	} else {
//		glDisable(name);
//	}
//}
//
//@end

CC3OpenGLES11StateTrackerServerCapability::CC3OpenGLES11StateTrackerServerCapability()
{
}

CC3OpenGLES11StateTrackerServerCapability::~CC3OpenGLES11StateTrackerServerCapability()
{
}

CC3OpenGLES11StateTrackerServerCapability* CC3OpenGLES11StateTrackerServerCapability::trackerForState(GLenum aName)
{
	CC3OpenGLES11StateTrackerServerCapability* pState = new CC3OpenGLES11StateTrackerServerCapability;
	if (pState) 
	{
		pState->autorelease();
		pState->initForState(aName, NULL);
		return pState;
	}
	
	return NULL;
}

CC3OpenGLES11StateTrackerServerCapability* CC3OpenGLES11StateTrackerServerCapability::trackerForState(GLenum aName, CC3GLESStateOriginalValueHandling origValueHandling)
{
	CC3OpenGLES11StateTrackerServerCapability* pState = new CC3OpenGLES11StateTrackerServerCapability;
	if (pState) 
	{
		pState->autorelease();
		pState->initForState(aName, origValueHandling);
		return pState;
	}
	
	return NULL;
}

void CC3OpenGLES11StateTrackerServerCapability::setGLValue()
{
	if (value) 
	{
		glEnable(name);
	} 
	else 
	{
		glDisable(name);
	}
}


#pragma mark -
#pragma mark CC3OpenGLES11StateTrackerClientCapability

//@implementation CC3OpenGLES11StateTrackerClientCapability
//
//-(void) setGLValue {
//	if (value) {
//		glEnableClientState(name);
//	} else {
//		glDisableClientState(name);
//	}
//}
//
//@end

CC3OpenGLES11StateTrackerClientCapability::CC3OpenGLES11StateTrackerClientCapability()
{
}

CC3OpenGLES11StateTrackerClientCapability::~CC3OpenGLES11StateTrackerClientCapability()
{
}

CC3OpenGLES11StateTrackerClientCapability* CC3OpenGLES11StateTrackerClientCapability::trackerForState(GLenum aName)
{
	CC3OpenGLES11StateTrackerClientCapability* pState = new CC3OpenGLES11StateTrackerClientCapability;
	if (pState) 
	{
		pState->autorelease();
		pState->initForState(aName, NULL);
		return pState;
	}
	
	return NULL;
}

void CC3OpenGLES11StateTrackerClientCapability::setGLValue()
{
	if (value) 
	{
		glEnableClientState(name);
	} 
	else 
	{
		glDisableClientState(name);
	}
}


#pragma mark -
#pragma mark CC3OpenGLES11ServerCapabilities

//@implementation CC3OpenGLES11ServerCapabilities
//
//@synthesize alphaTest;
//@synthesize blend;
//@synthesize clipPlanes;
//@synthesize colorLogicOp;
//@synthesize colorMaterial;
//@synthesize cullFace;
//@synthesize depthTest;
//@synthesize dither;
//@synthesize fog;
//@synthesize lighting;
//@synthesize lineSmooth;
//@synthesize multisample;
//@synthesize normalize;
//@synthesize pointSmooth;
//@synthesize pointSprites;
//@synthesize polygonOffsetFill;
//@synthesize rescaleNormal;
//@synthesize sampleAlphaToCoverage;
//@synthesize sampleAlphaToOne;
//@synthesize sampleCoverage;
//@synthesize scissorTest;
//@synthesize stencilTest;
//
//-(void) dealloc {
//	[alphaTest release];
//	[blend release];
//	[clipPlanes release];
//	[colorLogicOp release];
//	[colorMaterial release];
//	[cullFace release];
//	[depthTest release];
//	[dither release];
//	[fog release];
//	[lighting release];
//	[lineSmooth release];
//	[multisample release];
//	[normalize release];
//	[pointSmooth release];
//	[pointSprites release];
//	[polygonOffsetFill release];
//	[rescaleNormal release];
//	[sampleAlphaToCoverage release];
//	[sampleAlphaToOne release];
//	[sampleCoverage release];
//	[scissorTest release];
//	[stencilTest release];
//	[super dealloc];
//}
//
//-(CC3OpenGLES11StateTrackerServerCapability*) clipPlaneAt: (GLint) cpIndx {
//	return [clipPlanes objectAtIndex: cpIndx];
//}
//
//-(void) initializeTrackers {
//	self.alphaTest = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_ALPHA_TEST];
//	self.blend = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_BLEND];
//	self.clipPlanes = [NSMutableArray array];
//	
//	GLint platformMaxClipPlanes = [CC3OpenGLES11Engine engine].platform.maxClipPlanes.value;
//	for (int i = 0; i < platformMaxClipPlanes; i++) {
//		[clipPlanes addObject: [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_CLIP_PLANE0 + i]];
//	}
//
//	self.colorLogicOp = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_COLOR_LOGIC_OP];
//	self.colorMaterial = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_COLOR_MATERIAL];
//	self.cullFace = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_CULL_FACE];
//	self.depthTest = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_DEPTH_TEST];
//	self.dither = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_DITHER];
//	self.fog = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_FOG];
//	self.lighting = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_LIGHTING];
//	self.lineSmooth = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_LINE_SMOOTH];
//	self.multisample = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_MULTISAMPLE];
//	self.normalize = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_NORMALIZE];
//	self.pointSmooth = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_POINT_SMOOTH];
//
//	// Illegal GL enum when trying to read value of GL_POINT_SPRITE_OES.
//	self.pointSprites = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_POINT_SPRITE_OES
//															andOriginalValueHandling: kCC3GLESStateOriginalValueIgnore];
//	self.polygonOffsetFill = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_POLYGON_OFFSET_FILL];
//	self.rescaleNormal = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_RESCALE_NORMAL];
//	self.sampleAlphaToCoverage = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_SAMPLE_ALPHA_TO_COVERAGE];
//	self.sampleAlphaToOne = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_SAMPLE_ALPHA_TO_ONE];
//	self.sampleCoverage = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_SAMPLE_COVERAGE];
//	self.scissorTest = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_SCISSOR_TEST];
//	self.stencilTest = [CC3OpenGLES11StateTrackerServerCapability trackerForState: GL_STENCIL_TEST];
//}
//
//-(void) open {
//	LogTrace("Opening %@", [self class]);
//	[alphaTest open];
//	[blend open];
//	[self openTrackers: clipPlanes];
//	[colorLogicOp open];
//	[colorMaterial open];
//	[cullFace open];
//	[depthTest open];
//	[dither open];
//	[fog open];
//	[lighting open];
//	[lineSmooth open];
//	[multisample open];
//	[normalize open];
//	[pointSmooth open];
//	[pointSprites open];
//	[polygonOffsetFill open];
//	[rescaleNormal open];
//	[sampleAlphaToCoverage open];
//	[sampleAlphaToOne open];
//	[sampleCoverage open];
//	[scissorTest open];
//	[stencilTest open];
//}
//
//-(void) close {
//	LogTrace("Closing %@", [self class]);
//	[alphaTest close];
//	[blend close];
//	[self closeTrackers: clipPlanes];
//	[colorLogicOp close];
//	[colorMaterial close];
//	[cullFace close];
//	[depthTest close];
//	[dither close];
//	[fog close];
//	[lighting close];
//	[lineSmooth close];
//	[multisample close];
//	[normalize close];
//	[pointSmooth close];
//	[pointSprites close];
//	[polygonOffsetFill close];
//	[rescaleNormal close];
//	[sampleAlphaToCoverage close];
//	[sampleAlphaToOne close];
//	[sampleCoverage close];
//	[scissorTest close];
//	[stencilTest close];
//}
//
//-(NSString*) description {
//	NSMutableString* desc = [NSMutableString stringWithCapacity: 1000];
//	[desc appendFormat: @"%@:", [self class]];
//	[desc appendFormat: @"\n    %@ ", alphaTest];
//	[desc appendFormat: @"\n    %@ ", blend];
//	for (id t in clipPlanes) {
//		[desc appendFormat: @"\n    %@ ", t];
//	}
//	[desc appendFormat: @"\n    %@ ", colorLogicOp];
//	[desc appendFormat: @"\n    %@ ", colorMaterial];
//	[desc appendFormat: @"\n    %@ ", cullFace];
//	[desc appendFormat: @"\n    %@ ", depthTest];
//	[desc appendFormat: @"\n    %@ ", dither];
//	[desc appendFormat: @"\n    %@ ", fog];
//	[desc appendFormat: @"\n    %@ ", lighting];
//	[desc appendFormat: @"\n    %@ ", lineSmooth];
//	[desc appendFormat: @"\n    %@ ", multisample];
//	[desc appendFormat: @"\n    %@ ", normalize];
//	[desc appendFormat: @"\n    %@ ", pointSmooth];
//	[desc appendFormat: @"\n    %@ ", pointSprites];
//	[desc appendFormat: @"\n    %@ ", polygonOffsetFill];
//	[desc appendFormat: @"\n    %@ ", rescaleNormal];
//	[desc appendFormat: @"\n    %@ ", sampleAlphaToCoverage];
//	[desc appendFormat: @"\n    %@ ", sampleAlphaToOne];
//	[desc appendFormat: @"\n    %@ ", sampleCoverage];
//	[desc appendFormat: @"\n    %@ ", scissorTest];
//	[desc appendFormat: @"\n    %@ ", stencilTest];
//	return desc;
//}
//
//@end

CC3OpenGLES11ServerCapabilities::CC3OpenGLES11ServerCapabilities() :
	clipPlanes(NULL),
	alphaTest(NULL),
	blend(NULL),
	colorLogicOp(NULL),
	colorMaterial(NULL),
	cullFace(NULL),
	depthTest(NULL),
	dither(NULL),
	fog(NULL),
	lighting(NULL),
	lineSmooth(NULL),
	multisample(NULL),
	normalize(NULL),
	pointSmooth(NULL),
	pointSprites(NULL),
	polygonOffsetFill(NULL),
	rescaleNormal(NULL),
	sampleAlphaToCoverage(NULL),
	sampleAlphaToOne(NULL),
	sampleCoverage(NULL),
	scissorTest(NULL),
	stencilTest(NULL)
{
	
}

CC3OpenGLES11ServerCapabilities::~CC3OpenGLES11ServerCapabilities()
{
	clipPlanes->release();
	
	alphaTest->release();
	blend->release();
	colorLogicOp->release();
	colorMaterial->release();
	cullFace->release();
	depthTest->release();
	dither->release();
	fog->release();
	lighting->release();
	lineSmooth->release();
	multisample->release();
	normalize->release();
	pointSmooth->release();
	pointSprites->release();
	polygonOffsetFill->release();
	rescaleNormal->release();
	sampleAlphaToCoverage->release();
	sampleAlphaToOne->release();
	sampleCoverage->release();
	scissorTest->release();
	stencilTest->release();
}

CC3OpenGLES11ServerCapabilities* CC3OpenGLES11ServerCapabilities::tracker()
{
	CC3OpenGLES11ServerCapabilities* pState = new CC3OpenGLES11ServerCapabilities;
	if (pState) 
	{
		pState->initializeTrackers();
		pState->autorelease();
	}
	
	return pState;
}

void CC3OpenGLES11ServerCapabilities::open()
{
	//LogTrace("Opening %@", [self class]);
	alphaTest->open();
	blend->open();
	openTrackers(clipPlanes);
	colorLogicOp->open();
	colorMaterial->open();
	cullFace->open();
	depthTest->open();
	dither->open();
	// todo
	//fog->open();
	lighting->open();
	lineSmooth->open();
	multisample->open();
	normalize->open();
	pointSmooth->open();
	pointSprites->open();
	polygonOffsetFill->open();
	rescaleNormal->open();
	sampleAlphaToCoverage->open();
	sampleAlphaToOne->open();
	sampleCoverage->open();
	scissorTest->open();
	stencilTest->open();
}

void CC3OpenGLES11ServerCapabilities::close()
{
	//LogTrace("Closing %@", [self class]);
	alphaTest->close();
	blend->close();
	closeTrackers(clipPlanes);
	colorLogicOp->close();
	colorMaterial->close();
	cullFace->close();
	depthTest->close();
	dither->close();
	// todo
	//fog->close();
	lighting->close();
	lineSmooth->close();
	multisample->close();
	normalize->close();
	pointSmooth->close();
	pointSprites->close();
	polygonOffsetFill->close();
	rescaleNormal->close();
	sampleAlphaToCoverage->close();
	sampleAlphaToOne->close();
	sampleCoverage->close();
	scissorTest->close();
	stencilTest->close();
}

void CC3OpenGLES11ServerCapabilities::initializeTrackers()
{
	clipPlanes = cocos2d::CCArray::array();
	clipPlanes->retain();
	
	setAlphaTest(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_ALPHA_TEST));
	setBlend(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_BLEND));
	
	GLint platformMaxClipPlanes = CC3OpenGLES11Engine::engine()->getPlatform()->getMaxClipPlanes()->getValue();
	for (int i = 0; i < platformMaxClipPlanes; i++) 
	{
		clipPlanes->addObject(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_CLIP_PLANE0 + i));
	}
	
	 setColorLogicOp(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_COLOR_LOGIC_OP));
	 setColorMaterial(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_COLOR_MATERIAL));
	 setCullFace(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_CULL_FACE));
	 setDepthTest(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_DEPTH_TEST));
	 setDither(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_DITHER));
	 setFog(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_FOG));
	 setLighting(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_LIGHTING));
	 setLineSmooth(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_LINE_SMOOTH));
	 setMultisample(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_MULTISAMPLE));
	 setNormalize(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_NORMALIZE));
	 setPointSmooth(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_POINT_SMOOTH));
	
	// Illegal GL enum when trying to read value of GL_POINT_SPRITE_OES.
	 setPointSprites(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_POINT_SPRITE_OES, kCC3GLESStateOriginalValueIgnore));
	 setPolygonOffsetFill(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_POLYGON_OFFSET_FILL));
	 setRescaleNormal(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_RESCALE_NORMAL));
	 setSampleAlphaToCoverage(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_SAMPLE_ALPHA_TO_COVERAGE));
	 setSampleAlphaToOne(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_SAMPLE_ALPHA_TO_ONE));
	 setSampleCoverage(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_SAMPLE_COVERAGE));
	 setScissorTest(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_SCISSOR_TEST));
	 setStencilTest(CC3OpenGLES11StateTrackerServerCapability::trackerForState(GL_STENCIL_TEST));
}

CC3OpenGLES11StateTrackerServerCapability* CC3OpenGLES11ServerCapabilities::clipPlaneAt(GLint cpIndx)
{
	return (CC3OpenGLES11StateTrackerServerCapability*)clipPlanes->objectAtIndex(cpIndx);
}

#pragma mark -
#pragma mark CC3OpenGLES11ClientCapabilities

//@implementation CC3OpenGLES11ClientCapabilities
//
//@synthesize colorArray;
//@synthesize normalArray;
//@synthesize pointSizeArray;
//@synthesize vertexArray;
//
//-(void) dealloc {
//	[colorArray release];
//	[normalArray release];
//	[pointSizeArray release];
//	[vertexArray release];
//	[super dealloc];
//}
//
//-(void) initializeTrackers {
//	self.colorArray = [CC3OpenGLES11StateTrackerClientCapability trackerForState: GL_COLOR_ARRAY];
//	self.normalArray = [CC3OpenGLES11StateTrackerClientCapability trackerForState: GL_NORMAL_ARRAY];
//	self.pointSizeArray = [CC3OpenGLES11StateTrackerClientCapability trackerForState: GL_POINT_SIZE_ARRAY_OES];
//	self.vertexArray = [CC3OpenGLES11StateTrackerClientCapability trackerForState: GL_VERTEX_ARRAY];
//}	
//
//-(void) open {
//	LogTrace("Opening %@", [self class]);
//	[colorArray open];
//	[normalArray open];
//	[pointSizeArray open];
//	[vertexArray open];
//}
//
//-(void) close {
//	LogTrace("Closing %@", [self class]);
//	[colorArray close];
//	[normalArray close];
//	[pointSizeArray close];
//	[vertexArray close];
//}
//
//-(NSString*) description {
//	NSMutableString* desc = [NSMutableString stringWithCapacity: 300];
//	[desc appendFormat: @"%@:", [self class]];
//	[desc appendFormat: @"\n    %@ ", colorArray];
//	[desc appendFormat: @"\n    %@ ", normalArray];
//	[desc appendFormat: @"\n    %@ ", pointSizeArray];
//	[desc appendFormat: @"\n    %@ ", vertexArray];
//	return desc;
//}
//
//@end
			 
			 
CC3OpenGLES11ClientCapabilities::CC3OpenGLES11ClientCapabilities() :
	colorArray(NULL),
	normalArray(NULL),
	pointSizeArray(NULL),
	vertexArray(NULL)
{
	
}
			 
CC3OpenGLES11ClientCapabilities::~CC3OpenGLES11ClientCapabilities()
{
	colorArray->release();
	normalArray->release();
	pointSizeArray->release();
	vertexArray->release();
}

CC3OpenGLES11ClientCapabilities* CC3OpenGLES11ClientCapabilities::tracker()
{
	CC3OpenGLES11ClientCapabilities* pState = new CC3OpenGLES11ClientCapabilities;
	if (pState) 
	{
		pState->initializeTrackers();
		pState->autorelease();
	}
	
	return pState;
}
			 
void CC3OpenGLES11ClientCapabilities::open()
{
	 //LogTrace("Opening %@", [self class]);
	 colorArray->open();
	 normalArray->open();
	 pointSizeArray->open();
	 vertexArray->open();
}
			 
void CC3OpenGLES11ClientCapabilities::close()
{
	//LogTrace("Closing %@", [self class]);
	colorArray->close();
	normalArray->close();
	pointSizeArray->close();
	vertexArray->close();
}
			 
 void CC3OpenGLES11ClientCapabilities::initializeTrackers()
 {
	 setColorArray(CC3OpenGLES11StateTrackerClientCapability::trackerForState(GL_COLOR_ARRAY));
	 setNormalArray(CC3OpenGLES11StateTrackerClientCapability::trackerForState(GL_NORMAL_ARRAY));
	 setPointSizeArray(CC3OpenGLES11StateTrackerClientCapability::trackerForState(GL_POINT_SIZE_ARRAY_OES));
	 setVertexArray(CC3OpenGLES11StateTrackerClientCapability::trackerForState(GL_VERTEX_ARRAY));
 }
